/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package image.edge;

import image.edge.zerocross.ZeroCross;
import java.awt.image.BufferedImage;
import java.awt.image.Raster;
import java.awt.image.WritableRaster;
import java.util.Set;
import mask.ImageMask;

/**
 *
 * @author tommy
 */
public class LogEdgeDetector extends EdgeDetectorImpl {
	private double threshold;
	private double sigma;
	private int ksize; // kernelsize
	private ImageMask logMask;
	
	public LogEdgeDetector(BufferedImage src, double sigma, double threshold) {
		// odd kernel size > 6*sigma
		super(src, ((int)Math.ceil(sigma*3) * 2 + 1) / 2);
		ksize = (int)Math.ceil(sigma*3) * 2 + 1;
		this.threshold = threshold;
		this.sigma = sigma;
		
		logMask = new ImageMask(buildLoGKernel(), ksize);
	}

	public BufferedImage FindEdges() {
		Double[] logMagnitudes;
		Set<Integer[]> crossIndexes;
		ZeroCross cross;
		
		WritableRaster outRaster;
		Raster inRaster;
		
		outRaster = ret.getRaster();
		logMagnitudes = new Double[ret.getHeight()*ret.getWidth()];
		// get original image pixels
		inRaster = src.getData();
		
		logMagnitudes = logMask.applyMask(src);
		
		cross = new ZeroCross(ret, threshold);
		
		crossIndexes = cross.findCrossings(logMagnitudes);
		
		for (Integer[] crossIndex : crossIndexes) {
			outRaster.setSample(crossIndex[0], crossIndex[1], 0, 255);
		}
		
		return ret;
	}
	
	private double[][] buildLoGKernel() {
		double[][] logKernel;
		double xmapIndex, ymapIndex; // transform (x,y) to gaussian kernel coords
		double sigma2,sigma3;
		double exp, LoGValue;
		double sum = 0;
			
		logKernel = new double[ksize][ksize];
		sigma2 = sigma*sigma; //^2
		sigma3 = sigma*sigma*sigma; // ^3
		
		for (int y = 0 ; y < ksize ; y++) {
			for (int x = 0 ; x < ksize ; x++) {
				xmapIndex = x - ksize/2;
				ymapIndex = y - ksize/2;
				exp = Math.exp(-((xmapIndex*xmapIndex + ymapIndex*ymapIndex) / (2 * sigma2) ));
				LoGValue = -(1d / (Math.sqrt(2 * Math.PI) * sigma3)) * 
					(2 - (xmapIndex*xmapIndex + ymapIndex + ymapIndex) / sigma2) * exp;
				logKernel[y][x] = LoGValue;
				sum += LoGValue;
			}
		}
		
		// Operation to make kernel elements sum to 0
		sum /= (ksize*ksize);
		
		for (int y = 0 ; y < ksize ; y++) {
			for (int x = 0 ; x < ksize ; x++) {
				logKernel[y][x] -= sum;
			}
		}
		return logKernel;
	}
}
